package com.shopping.product.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shopping.common.utils.PageUtils;
import com.shopping.common.utils.Query;
import com.shopping.product.dao.CategoryDao;
import com.shopping.product.entity.CategoryEntity;
import com.shopping.product.service.CategoryBrandRelationService;
import com.shopping.product.service.CategoryService;
import com.shopping.product.vo.Catalog2Vo;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;


@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {

    @Resource
    CategoryBrandRelationService categoryBrandRelationService;

    @Resource
    StringRedisTemplate stringRedisTemplate;

    @Resource
    RedissonClient redisson;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<CategoryEntity> page = this.page(
                new Query<CategoryEntity>().getPage(params),
                new QueryWrapper<CategoryEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * 后台页面 商品系统 分类维护
     * CategoryEntity实体树
     *
     * @return List<CategoryEntity>
     */
    @Override
    public List<CategoryEntity> listWithTree() {
        //1.查出所有分类
        List<CategoryEntity> entities = baseMapper.selectList(null);
        //2.组装成父子的树形结构
        List<CategoryEntity> collect = entities.stream().filter(categoryEntity ->
                categoryEntity.getParentCid() == 0
        ).collect(Collectors.toList());

        List<CategoryEntity> collect1 = collect.stream().peek(menu ->
                menu.setChildren(getChildren(menu, entities))
        ).collect(Collectors.toList());

        return collect1.stream().sorted(
                Comparator.comparingInt(CategoryEntity::getSort)
        ).collect(Collectors.toList());
    }

    /**
     * 后台页面 商品系统 分类维护
     * 通过id删除菜单
     *
     * @param asList List<Long> 含分类id的list
     */
    @Override
    public void removeMenuByIds(List<Long> asList) {
        //todo 删除当前菜单时,检查其他地方是否引用
        baseMapper.deleteBatchIds(asList);
    }

    /**
     * 找到catelogId的完整路径
     *
     * @param catelogId
     * @return
     */
    @Override
    public Long[] findCatelogPath(Long catelogId) {
        List<Long> path = new ArrayList<>();
        List<Long> parentPath = this.findParentPath(catelogId, path);
        Collections.reverse(parentPath);
        return parentPath.toArray(new Long[0]);
    }

    /**
     * 后台页面 商品系统 分类维护
     * 更新CategoryEntity实体
     *
     * @param category CategoryEntity实体
     */
    @CacheEvict(value = "category", allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateCascade(CategoryEntity category) {
        this.updateById(category);
        categoryBrandRelationService.updateCategory(category.getCatId(), category.getName());
    }

    /**
     * 获得分类菜单1级列表
     *
     * @return List<CategoryEntity>
     */
    @Cacheable(value = {"category"}, key = "#root.method.name")
    @Override
    public List<CategoryEntity> getLevel1Category() {
        System.out.println("缓存....");
        long start = System.currentTimeMillis();
        QueryWrapper<CategoryEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("parent_cid", 0);
        List<CategoryEntity> list = baseMapper.selectList(wrapper);
        long end = System.currentTimeMillis();
        long time = end - start;
        System.out.println("用时: " + time);
        return list;
    }

    /**
     * 获得json格式的catalog map
     *
     * @return Map<String, List < Catalog2Vo>>
     */
    @Cacheable(value = "category", key = "#root.method.name")
    @Override
    public Map<String, List<Catalog2Vo>> getCatalogJson() {
        return getCatalogJsonWithRedisLock();
    }

    private Map<String, List<Catalog2Vo>> getCatalogJsonWithRedisLock() {
        RLock rLock = redisson.getLock("catalog-json-lock");
        //上分布式锁
        rLock.lock();
        Map<String, List<Catalog2Vo>> catalogJsonFromDb;
        try {
            catalogJsonFromDb = getCatalogJsonFromDb();
        } finally {
            rLock.unlock();
        }
        return catalogJsonFromDb;
    }

    private List<CategoryEntity> getParentCid(List<CategoryEntity> lv1List, Long catId) {
        return lv1List.stream().filter(item ->
                item.getParentCid().equals(catId)
        ).collect(Collectors.toList());
    }

    private Map<String, List<Catalog2Vo>> getCatalogJsonFromDb() {
        //查出所有分类
        List<CategoryEntity> entityList = baseMapper.selectList(null);
        //列出父id为0的list
        List<CategoryEntity> lv1List = getParentCid(entityList, 0L);
        //给map传入list的size,减少map扩容次数
        Map<String, List<Catalog2Vo>> map = new HashMap<>(lv1List.size());
        lv1List.forEach(lv1 -> {
            List<CategoryEntity> lv2List = getParentCid(entityList, lv1.getCatId());
            List<Catalog2Vo> catalog2Vos;
            if (lv2List != null) {
                catalog2Vos = new ArrayList<>(lv2List.size() + 1);
                lv2List.forEach(lv2 -> {
                    List<CategoryEntity> lv3List = getParentCid(entityList, lv2.getCatId());
                    //Catalog2Vo实体
                    Catalog2Vo catalog2Vo = new Catalog2Vo();
                    catalog2Vo.setCatalog1Id(lv1.getCatId().toString());
                    catalog2Vo.setId(lv2.getCatId().toString());
                    catalog2Vo.setName(lv2.getName());
                    if (lv3List != null) {
                        //Catalog2Vo的List<Catelog3Vo>属性
                        List<Catalog2Vo.Catelog3Vo> catelog3Vos = new ArrayList<>(lv3List.size() + 1);
                        lv3List.forEach(lv3 -> {
                            Catalog2Vo.Catelog3Vo catelog3Vo = new Catalog2Vo.Catelog3Vo();
                            catelog3Vo.setCatalog2Id(lv2.getCatId().toString());
                            catelog3Vo.setId(lv3.getCatId().toString());
                            catelog3Vo.setName(lv3.getName());
                            //添加cate3log3Vos
                            catelog3Vos.add(catelog3Vo);
                        });
                        //Catalog2Vo的子分类
                        catalog2Vo.setCatalog3List(catelog3Vos);
                    }
                    //catalog2Vos
                    catalog2Vos.add(catalog2Vo);
                });
            } else {
                catalog2Vos = new ArrayList<>();
            }
            map.put(lv1.getCatId().toString(), catalog2Vos);
        });
        return map;
    }

    private List<Long> findParentPath(Long catelogId, List<Long> path) {
        // 收集当前节点id
        path.add(catelogId);
        CategoryEntity byId = this.getById(catelogId);
        if (byId.getParentCid() != 0) {
            findParentPath(byId.getParentCid(), path);
        }
        return path;
    }

    private List<CategoryEntity> getChildren(CategoryEntity root, List<CategoryEntity> all) {
        //先过滤
        List<CategoryEntity> collect = all.stream().filter(categoryEntity ->
                categoryEntity.getParentCid().equals(root.getCatId())
        ).collect(Collectors.toList());
        //递归调用
        List<CategoryEntity> collect1 = collect.stream().peek(categoryEntity ->
                categoryEntity.setChildren(getChildren(categoryEntity, all))
        ).collect(Collectors.toList());
        //排序
        return collect1.stream().sorted(Comparator.comparingInt(menu ->
                (menu.getSort() == null ? 0 : menu.getSort()))
        ).collect(Collectors.toList());
    }

}
